﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace DataCenter.Share
{
    public delegate string ExpressionComputeCallbackDelegate(Operators oper, string value0, string value1);
    public static class Algorithm
    {
        public static int[] ParseTupleString(string idStr)
        {
            List<int> idList = new List<int>();
            string[] tupleArray = idStr.Split(new char[] { ',', '{', '}' },
                StringSplitOptions.RemoveEmptyEntries);
            foreach (string tupleString in tupleArray)
            {
                if (tupleString.StartsWith("[") && tupleString.EndsWith("]"))
                {
                    int[] ids = ParseArrayString(tupleString);
                    if (ids != null) idList.AddRange(ids);
                }
                else
                {
                    int iValue;
                    if (int.TryParse(tupleString, out iValue))
                        idList.Add(iValue);
                }
            }
            idList.Sort();
            for (int i = 1; i < idList.Count; i++)
            {
                if (idList[i - 1] == idList[i])
                {
                    idList.RemoveAt(i);
                    i -= 1;
                }
            }
            return idList.ToArray();
        }
        public static int[] ParseArrayString(string arrayString)
        {
            if (!Regex.IsMatch(arrayString, @"^\[(\s*(-?\d+)\s*)\.(\s*(-?\d+)\s*)\.(\s*(-?\d+)\s*)\]$"))
                return null;

            string[] strArray = arrayString.Split(new char[] { '[', ']', '.' },
                StringSplitOptions.RemoveEmptyEntries);

            int[] intArray = Array.ConvertAll<string, int>(strArray,
                new Converter<string, int>(
                    delegate(string value)
                    {
                        return Convert.ToInt32(value);
                    }));

            int startIndex = intArray[0];
            int step = intArray[1];
            int endIndex = intArray[2];

            List<int> idList = new List<int>();

            if (startIndex < endIndex)
            {
                if (step > 0)
                {
                    for (int id = startIndex; id <= endIndex; id += step)
                    {
                        idList.Add(id);
                    }
                }
            }
            else if (startIndex > endIndex)
            {
                if (step < 0)
                {
                    for (int id = endIndex; id >= startIndex; id -= step)
                    {
                        idList.Add(id);
                    }
                }
            }
            else
            {
                idList.Add(startIndex);
            }

            return idList.ToArray();
        }

        public static string InfixToPostfix(string expression)
        {
            Stack<char> operators = new Stack<char>();
            StringBuilder result = new StringBuilder();
            for (int i = 0; i < expression.Length; i++)
            {
                char ch = expression[i];
                if (char.IsWhiteSpace(ch)) continue;
                switch (ch)
                {
                    case '+':
                    case '-':
                        while (operators.Count > 0)
                        {
                            char c = operators.Pop();
                            if (c == '(')
                            {
                                operators.Push(c);
                                break;
                            }
                            else
                            {
                                result.Append(c);
                            }
                        }
                        operators.Push(ch);
                        result.Append(" ");
                        break;
                    case '*':
                    case '/':
                        while (operators.Count > 0)
                        {
                            char c = operators.Pop();
                            if (c == '(')
                            {
                                operators.Push(c);
                                break;
                            }
                            else
                            {
                                if (c == '+' || c == '-')
                                {
                                    operators.Push(c);
                                    break;
                                }
                                else
                                {
                                    result.Append(c);
                                }
                            }
                        }
                        operators.Push(ch);
                        result.Append(" ");
                        break;
                    case '(':
                        operators.Push(ch);
                        break;
                    case ')':
                        while (operators.Count > 0)
                        {
                            char c = operators.Pop();
                            if (c == '(')
                            {
                                break;
                            }
                            else
                            {
                                result.Append(c);
                            }
                        }
                        break;
                    default:
                        result.Append(ch);
                        break;
                }
            }
            while (operators.Count > 0)
            {
                result.Append(operators.Pop());
            }
            return result.ToString();
        }
        public static string ExpressionCompute(string expression, ExpressionComputeCallbackDelegate callback)
        {
            Stack<string> results = new Stack<string>();
            string x, y;
            for (int i = 0; i < expression.Length; i++)
            {
                char ch = expression[i];
                if (char.IsWhiteSpace(ch)) continue;
                switch (ch)
                {
                    case '+':
                        y = results.Pop();
                        x = results.Pop();
                        results.Push(callback(GetOperator("+"), x, y));
                        break;
                    case '-':
                        y = results.Pop();
                        x = results.Pop();
                        results.Push(callback(GetOperator("-"), x, y));
                        break;
                    case '*':
                        y = results.Pop();
                        x = results.Pop();
                        results.Push(callback(GetOperator("*"), x, y));
                        break;
                    case '/':
                        y = results.Pop();
                        x = results.Pop();
                        results.Push(callback(GetOperator("/"), x, y));
                        break;
                    default:
                        int pos = i;
                        StringBuilder operand = new StringBuilder();
                        do
                        {
                            operand.Append(expression[pos]);
                            pos += 1;
                        } while (char.IsDigit(expression[pos]) ||
                                 expression[pos] == '.' ||
                                 expression[pos] == '[' ||
                                 expression[pos] == ']');
                        i = pos - 1;
                        results.Push(operand.ToString());
                        break;
                }
            }
            return results.Peek();
        }
        public static Operators GetOperator(string oper)
        {
            switch (oper)
            {
                case "+": return Operators.Add;
                case "-": return Operators.Sub;
                case "*": return Operators.Mul;
                case "/": return Operators.Div;
                default:
                    throw new InvalidOperationException("无效的运算符号\"" + oper + "\"");
            }
        }
        public static float Calculate(Operators oper, float value0, float value1)
        {
            switch (oper)
            {
                case Operators.Add: return value0 + value1;
                case Operators.Sub: return value0 - value1;
                case Operators.Mul: return value0 * value1;
                case Operators.Div: return value0 / value1;
                default:
                    throw new InvalidOperationException("无效的运算符");
            }
        }
    }    
}
